package json;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;

/**
 * Jackson util 这只是个再也简单不过的demo.实验性产品，项目中不可采用。
 * 
 * @author yangjuntao@p-an.com 2013年11月18日
 */
public class JacksonHelper
{
	static Logger _Logger = LoggerFactory.getLogger(JacksonHelper.class);

	private static ObjectMapper mapper;

	/**
	 * 一个破ObjectMapper而已，你为什么不直接new 还搞的那么复杂。接下来的几篇文章我将和你一起研究这个问题
	 * 
	 * @param createNew
	 *            是否创建一个新的Mapper
	 */
	public static synchronized ObjectMapper getObjectMapper(final boolean createNew)
	{
		if (createNew)
		{
			return new ObjectMapper();
		}
		else if (mapper == null)
		{
			mapper = new ObjectMapper();
		}
		return mapper;
	}

	/**
	 * 这里异常都未进行处理，而且流的关闭也不规范。开发中请勿这样写，如果发生异常流关闭不了
	 */
	public static String beanToJson(final Object obj) throws IOException
	{
		StringWriter writer = new StringWriter();
		JsonGenerator jsonGenerator = new JsonFactory().createGenerator(writer);
		getObjectMapper(false).writeValue(jsonGenerator, obj);
		jsonGenerator.close();
		String json = writer.toString();
		writer.close();
		return json;
	}

	public static Object jsonToBean(final String json, final Class<?> cls) throws Exception
	{
		Object vo = getObjectMapper(false).readValue(json, cls);
		return vo;
	}

	/**
	 * 使用JsonNode findValuesAsText方法从实体中取出所有匹配的值
	 */
	public static List<String> getValueByFind(final JsonNode node, final String path) throws Exception
	{
		List<String> values = new ArrayList<String>();
		/**
		 * 这里提供两种方法:<br>
		 * 一种是:它会返回List<String> values = node.findValuesAsText(path); <br>
		 * 一种是:下面用的,它会直接把找到的value填到你传入的集合中;
		 */
		node.findValuesAsText(path, values);
		_Logger.debug(Arrays.toString(values.toArray()));
		return values;
	}

	/**
	 * 查找当前Node中第一个匹配的值
	 */
	public static int getFirstValueByFind(final JsonNode node, final String path) throws Exception
	{
		/*
		 * 注意这点不能使用getTextValue()方法，因为找到的值为Int类型的所以使用getTextValue是查不到值的。
		 * 不过如果想返回String字符串可以使用asText()方法。这里使用asInt是为了看到其实JackSon是可以直接返回相应类型的值的。
		 */
		int value = node.findValue(path).asInt();
		_Logger.debug("getFirstValueByFind : " + value);
		return value;
	}

	/**
	 * 从json中读取tagPath处的值 tagPath用 : 分隔
	 */
	public static List<String> readValueFromJson(final String json, final String tagPath) throws Exception
	{
		List<String> value = new ArrayList<String>();
		if (Strings.isNullOrEmpty(json) || (Strings.isNullOrEmpty(tagPath)))
		{
			return value;
		}
		ObjectMapper mapper = getObjectMapper(false);
		String[] path = tagPath.split(":");
		JsonNode node = mapper.readTree(json);
		getJsonValue(node, path, value, 1);
		return value;
	}

	public static void getJsonValue(JsonNode node, final String[] path, final List<String> values, final int nextIndex)
	{
		if (isEmpty(node))
		{
			return;
		}
		// 是路径的最后就直接取值
		if (nextIndex == path.length)
		{
			if (node.isArray())
			{
				for (int i = 0; i < node.size(); i++)
				{
					JsonNode child = node.get(i).get(path[nextIndex - 1]);
					if (isEmpty(child))
					{
						continue;
					}
					values.add(child.toString());
				}
			}
			else
			{
				JsonNode child = node.get(path[nextIndex - 1]);
				if (!isEmpty(child))
				{
					values.add(child.toString());
				}
			}
			return;
		}
		// 判断是Node下是集合还是一个节点
		node = node.get(path[nextIndex - 1]);
		if (node.isArray())
		{
			for (int i = 0; i < node.size(); i++)
			{
				getJsonValue(node.get(i), path, values, nextIndex + 1);
			}
		}
		else
		{
			getJsonValue(node, path, values, nextIndex + 1);
		}
	}

	/**
	 * 判断对象是否为空
	 */
	public static boolean isEmpty(final Object obj)
	{
		boolean result = true;
		if (obj == null)
		{
			return true;
		}
		if (obj instanceof String)
		{
			result = (obj.toString().trim().length() == 0) || obj.toString().trim().equals("null");
		}
		else
		{
			result = ((obj == null) || (obj.toString().trim().length() < 1)) ? true : false;
		}
		return result;
	}

}
